package cn.edu.sjtu.se.dslab.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import cn.edu.sjtu.se.dslab.action.bean.PageBean;
import cn.edu.sjtu.se.dslab.auth.CommonVariableModel;
import cn.edu.sjtu.se.dslab.auth.User;
import cn.edu.sjtu.se.dslab.component.aadl.AADLTemplate;
import cn.edu.sjtu.se.dslab.component.data.AvionicsEquipment;
import cn.edu.sjtu.se.dslab.component.data.DomainEntity;
import cn.edu.sjtu.se.dslab.component.design.DesignPatternComponent;
import cn.edu.sjtu.se.dslab.component.design.DesignPatternType;
import cn.edu.sjtu.se.dslab.component.design.generate.DisplayZoneGenerator;
import cn.edu.sjtu.se.dslab.component.design.util.DesignPatternComponentUtil;
import cn.edu.sjtu.se.dslab.component.dp.parse.DesignPatternInstanceBean;
import cn.edu.sjtu.se.dslab.component.dp.parse.Property;
import cn.edu.sjtu.se.dslab.component.method.ComponentInterface;
import cn.edu.sjtu.se.dslab.component.method.InterfaceMethod;
import cn.edu.sjtu.se.dslab.component.method.util.MethodComponentLink;
import cn.edu.sjtu.se.dslab.component.method.util.MethodComponentTool;
import cn.edu.sjtu.se.dslab.helper.ApplicationContextHelpler;
import cn.edu.sjtu.se.dslab.project.BusZone;
import cn.edu.sjtu.se.dslab.project.DisplayZone;
import cn.edu.sjtu.se.dslab.project.EntityZone;
import cn.edu.sjtu.se.dslab.project.EntityZoneCategory;
import cn.edu.sjtu.se.dslab.project.PGroup;
import cn.edu.sjtu.se.dslab.project.Project;
import cn.edu.sjtu.se.dslab.service.IAvionicsEquipmentService;
import cn.edu.sjtu.se.dslab.service.IBusZoneService;
import cn.edu.sjtu.se.dslab.service.IButtonService;
import cn.edu.sjtu.se.dslab.service.IDesignPatternComponentService;
import cn.edu.sjtu.se.dslab.service.IDesignPatternService;
import cn.edu.sjtu.se.dslab.service.IDisplayZoneService;
import cn.edu.sjtu.se.dslab.service.IDomainEntityService;
import cn.edu.sjtu.se.dslab.service.IEntityZoneCategoryService;
import cn.edu.sjtu.se.dslab.service.IEntityZoneService;
import cn.edu.sjtu.se.dslab.service.IEquipmentCategoryService;
import cn.edu.sjtu.se.dslab.service.IInterfaceMethodService;
import cn.edu.sjtu.se.dslab.service.IMethodComponentService;
import cn.edu.sjtu.se.dslab.service.IPGroupService;
import cn.edu.sjtu.se.dslab.service.IPositionService;
import cn.edu.sjtu.se.dslab.service.IProjectService;
import cn.edu.sjtu.se.dslab.service.IUserProjectService;
import cn.edu.sjtu.se.dslab.service.IUserService;
import cn.edu.sjtu.se.dslab.service.IVariableService;
import cn.edu.sjtu.se.dslab.util.FileUtil;

@Controller
@RequestMapping(value = "/designPatternCategory")
public class DesignPatternCategoryController {
	private static final Logger logger = Logger.getLogger(DesignPatternCategoryController.class);

	@Resource(name = "projectService")
	IProjectService projectService;

	@Resource(name = "pgroupService")
	IPGroupService pgroupService;

	@Resource(name = "userService")
	IUserService userService;
	
	@Resource(name="userProjectService")
	IUserProjectService userProjectService;
	
	@Resource(name = "entityZoneService")
	IEntityZoneService entityZoneService;
	
	@Resource(name = "busZoneService")
	IBusZoneService busZoneService;

	@Resource(name = "designPatternComponentService")
	IDesignPatternComponentService designPatternComponentService;

	@Resource(name = "designPatternService")
	IDesignPatternService designPatternService;

	@Resource(name = "domainEntityService")
	IDomainEntityService domainEntityService;

	@Resource(name = "avionicsEquipmentService")
	IAvionicsEquipmentService avionicsEquipmentService;

	@Resource(name = "equipmentCategoryService")
	IEquipmentCategoryService equipmentCategoryService;

	@Resource(name = "interfaceMethodService")
	IInterfaceMethodService interfaceMethodService;

	@Resource(name = "methodComponentTool")
	MethodComponentTool methodComponentTool;

	@Resource(name = "methodComponentService")
	IMethodComponentService methodComponentService;

	@Resource(name = "buttonService")
	IButtonService buttonService;
	
	@Resource(name = "displayZoneService")
	IDisplayZoneService displayZoneService;
	
	@Resource(name="designPatternComponentUtil")
	DesignPatternComponentUtil designPatternComponentUtil;
	
	@Resource(name="positionService")
	IPositionService positionService;
	
	@Resource(name="variableService")
	IVariableService variableService;
	
	@Resource(name = "entityZoneCategoryService")
	IEntityZoneCategoryService entityZoneCategoryService;
	
	//DesignPatternCategory is to organize desingpattern component
	@RequestMapping(value = "/add", method = RequestMethod.POST)
	public String addDesignPatternCateogry(Project project, Long groupID) {
		Subject user1 = SecurityUtils.getSubject();
		if (user1 != null) {
			CommonVariableModel model = (CommonVariableModel) user1
					.getPrincipals().getPrimaryPrincipal();
			project.setOwner(model.getUser());
			User user = model.getUser();
			PGroup pgroup = pgroupService.getPGroupById(groupID);
			project.setPgroup(pgroup);
			// create the project folder under the user's folder
			StringBuffer folderPath = new StringBuffer("userdata/");
			folderPath.append(user.getUsername()).append("/")
					.append("dpCategory/").append(project.getName()).append("/");
			FileUtil.createDirectorys(folderPath.toString());
			project.setFolderPath(folderPath.toString());
			projectService.addDesignPatternCategory(project);
		} else {
			System.out.println("no user logined");
		}

		return "redirect:/designPatternCategory/list";
	}
	
	/**
	 * 检索设计模式组件
	 * @param pageNUm
	 * @param name
	 * @param description
	 * @return
	 */
	@RequestMapping(value = "/query", method = RequestMethod.POST)
	@ResponseBody
	public Map<String, Object> queryDesignPatternCategory(
			@RequestParam(value = "pageNum", defaultValue = "1") int pageNUm,
			@RequestParam(value = "query_name", defaultValue = "") String name,
			@RequestParam(value = "query_des", defaultValue = "") String description,
			@RequestParam(value = "groupid", defaultValue = "0") long groupid) {
		logger.info("pageNUm:"+pageNUm+"|query_name:"+name+"|query_des:"+description+"|groupid:"+groupid);
		Map<String, Object> modelMap = new HashMap<String, Object>(4);
		try {
			//PageBean<AADLTemplate> bean = aadlTemplateService
			//		.getPageBeanByAttr(pageNUm, name, description,Long.parseLong(groupid));
			//List<Project> projects = projectService.getDesignPatternCategoryList();
			List<Project> projects = projectService.getDesignPatternCategoryByAttr(pageNUm, name, description, groupid);
			
			for (Project p: projects){
				p.setModel(null);
				p.getPgroup().setProjects(null);
				p.getPgroup().setUsers(null);
				p.getOwner().setGroupsList(null);  //角色
				p.getOwner().setPermsList(null);
				p.getOwner().setpGroups(null); //群组
				p.setDesignPatternComponents(null);
			}
			modelMap.put("designPatternCategorys", projects);
//			List<Map<String, String>> data = new ArrayList<Map<String, String>>();
//			if (bean != null && bean.getList() != null) {
//				for (int i = 0; i < bean.getList().size(); i++) {
//					Map<String, String> map = new HashMap<String, String>();
//					map.put(URI,
//							bean.getList().get(i).getUri().replace(":", "/"));
//					map.put(NAME, bean.getList().get(i).getName());
//					map.put(DESCRIPTION, bean.getList().get(i).getDescription());
//					data.add(map);
//				}
//				modelMap.put("currentNum", bean.getCurrentPage());
//				modelMap.put("totalNum", bean.getTotalPage());
//				modelMap.put("data", data);
//				modelMap.put("success", "true");
//			} else {
//				modelMap.put("success", "false");
//			}
			modelMap.put("success", "true");
			return modelMap;
		} catch (Exception e) {
			e.printStackTrace();
			modelMap.put("success", "false");
		}
		return modelMap;
	}
	
	
	@RequestMapping(value = "/{projectId}/select", method = RequestMethod.GET)
	public ModelAndView selectDesignPatternCategory(@PathVariable(value="projectId")long projectId){
		ModelAndView mav = new ModelAndView();
		mav.setViewName("selectDesignPatternCategory");
		List<PGroup> groups = pgroupService.getPGroupList();
		mav.addObject("groups", groups);
		mav.addObject("projectId", projectId);
		return mav;
	}
	
	@RequestMapping(value = "/import", method = RequestMethod.POST)
	@ResponseBody
	public Map<String,String> selectDesignPatternCategory(long projectId,long designPatternCategoryId){
		Map<String,String> modelMap = new HashMap<String,String>();
		logger.info("Project Id :" + projectId);
		logger.info("Design Pattern Category Id:" + designPatternCategoryId);
		try{
			designPatternComponentUtil.importDesignPatternComponents(projectId, designPatternCategoryId);
			modelMap.put("result", Boolean.TRUE.toString());
		}catch(Exception ex){
			ex.printStackTrace();
			modelMap.put("result", Boolean.FALSE.toString());
		}
		return modelMap;
	}
	
	

	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public ModelAndView getProjectList() {
		ModelAndView mav = new ModelAndView();
		mav.setViewName("manageDesignPatternCategory");
		User user = getUser();
		if (user != null){
			//List<Project> projects = projectService.getDesignPatternCategoryByUser(user);
			List<Project> projects = projectService.getDesignPatternCategoryList();
			mav.addObject("designPatternCategorys", projects.iterator());
			mav.addObject("user", user);
		}
		return mav;
	}
	
	@RequestMapping(value = "/menu", method = RequestMethod.GET)
	@ResponseBody
	public Project getProjectInfo() {
		Subject user = SecurityUtils.getSubject();
		if (user != null) {
			CommonVariableModel model = (CommonVariableModel) user
					.getPrincipals().getPrimaryPrincipal();
			long projectId = model.getProjectId();
			ModelAndView mav = new ModelAndView();
			mav.setViewName("projectMenu");
			if (0 == projectId){ 
				logger.info("No selected Project");
				return null;
			}
			Project project = projectService.getProjectById(projectId);
			project.setModel(null);
			project.setDesignPatternComponents(null);
			project.setOwner(null);
			project.setPgroup(null);
			mav.addObject("project", project);
			return project;
		} else {
			System.out.println("no login user");
			return null;
		}
	}
	
	@RequestMapping(value = "/list/{projectId}", method = RequestMethod.GET)
	public ModelAndView getProjectInfo(@PathVariable(value = "projectId") Long projectId) {
		Subject user = SecurityUtils.getSubject();
		if (user != null) {
			CommonVariableModel model = (CommonVariableModel) user
					.getPrincipals().getPrimaryPrincipal();
			model.setProjectId(projectId);
			System.out.println("set project id:" + projectId);
		} else {
			System.out.println("no login user");
		}
		ModelAndView mav = new ModelAndView();
		mav.setViewName("home");
		//List<Project> projects = projectService.getProjectList();
//		mav.addObject("projects", projects);
//		if (projectId != null) {
//			Project project = projectService.getProjectById(projectId);
//			return project;
//		}
		return mav;
	}

	@RequestMapping(value = "/{designPatternCategoryId}/design_pattern_component/{type}/{operation}", method = RequestMethod.GET)
	public ModelAndView getDesignPatternComponent(
			@PathVariable(value = "type") String type,
			@PathVariable(value = "operation")String operation,
			@PathVariable(value = "designPatternCategoryId") long designPatternCategoryId
			) {
		ModelAndView mav = new ModelAndView();

		//String dpcUri = DesignPatternComponentServiceImpl
		//		.toDesignPatternComponentUri(type, uri);
		DesignPatternComponent component = designPatternComponentService.getDesignPatternCommponentByType(
				designPatternCategoryId, DesignPatternType.valueOf(type.toUpperCase()));
		DesignPatternInstanceBean dpiBean = designPatternComponentService
				.getDesignPatternInstanceBean(component.getUri());

		mav.addObject("dpiName", dpiBean.getName());
		mav.addObject("dpcUri", component.getUri());
		Project project = projectService.getProjectById(designPatternCategoryId);
		mav.addObject("project", project);
		
		List<Project> projects = projectService.getProjectList();
		mav.addObject("projects", projects.iterator());
		
		if ("edit".equals(operation)){
			mav.addObject("isEdit", Boolean.TRUE.toString());
		}

		switch (DesignPatternType.valueOf(type.toUpperCase())) {
		case BUS:
			List<EntityZone> entityZones = entityZoneService.getEntityZoneByProject(designPatternCategoryId);
			mav.addObject("entityZones", entityZones);
			
			List<BusZone> busZones = busZoneService.getBusZoneByProject(designPatternCategoryId);
			mav.addObject("busZones", busZones);
			
			List<DomainEntity> domainEntities = domainEntityService
					.getAllDomainEntity();

			mav.addObject("data_components", domainEntities);

			//List<AvionicsEquipment> equipmentList = aadlParser
			//		.parseAADLToEquipmentList(file);
			//List<AvionicsEquipment> equipmentList = new ArrayList<AvionicsEquipment>();
			List<AvionicsEquipment> equipmentList  = avionicsEquipmentService.getAllAvionicsEquipmentList();
			
			List<AvionicsEquipment> busList = new ArrayList<AvionicsEquipment>();
			List<AvionicsEquipment> outterEquipmentList = new ArrayList<AvionicsEquipment>();
			for (AvionicsEquipment equipment : equipmentList) {
				if (equipment.getEquiptype().equals(
						AvionicsEquipment.EQUIPMENT_TYPE_BUS)) {
					busList.add(equipment);
				} else if (equipment.getEquiptype().equals(
						AvionicsEquipment.EQUIPMENT_TYPE_OUTTER_DEVICE)) {
					outterEquipmentList.add(equipment);
				}
			}
			mav.addObject("buses", busList);
			mav.addObject("outterEquipments", outterEquipmentList);

			//只是接口
			//List<InterfaceMethod> interfaceMethods = interfaceMethodService
			//		.getAllInterfaceMethod();
			//mav.addObject("interfaceMethods", interfaceMethods);
			
			//
			List<MethodComponentLink> methodComponentLinks_bus = methodComponentTool.getComponentLinksByInterfaceType(
					ComponentInterface.INTERFACE_TYPE_BUS_COM);
			mav.addObject("methodComponentLinks", methodComponentLinks_bus);
			

			List<Property> properties = dpiBean.getPropertyByName("equipment");
			List<AvionicsEquipment> existEquipments = new ArrayList<AvionicsEquipment>();
			for (Property p : properties) {
				AvionicsEquipment aEquipment = avionicsEquipmentService
						.getAvionicsEquipmentByUri(p.getValue());
				if (aEquipment != null)
					existEquipments.add(aEquipment);
			}
			mav.addObject("exist_equipments", existEquipments);
			mav.setViewName("configBusDesignPatternComponent");
			return mav;
		case DISPLAY:
			List<DomainEntity> dDomainEntities = domainEntityService.getAllDomainEntity();
			mav.addObject("data_components", dDomainEntities);
			mav.addObject("exist_pages", dpiBean.getInstances());
			mav.addObject("positions", positionService.getPositionList());
			mav.addObject("variables", variableService.getValidByProject(designPatternCategoryId));
			
			List<DisplayZone> displayZones = displayZoneService.getDisplayZoneByProject(designPatternCategoryId);
			mav.addObject("displayZones", displayZones);
			for (DisplayZone displayZone : displayZones){
				DomainEntity entity = domainEntityService.getDomainEntityByUri(displayZone.getEntityUri());
				if (entity!=null){
					displayZone.setEntityUri(entity.getName());
				}
			}
			
			List<DomainEntity> domainEntities2 = domainEntityService
					.getAllDomainEntity();
			mav.addObject("domainEntitys", domainEntities2);
			
			
			//mav.addObject("interfaceMethods", interfaceMethods);
			List<MethodComponentLink> methodComponentLinks_display = methodComponentTool.getComponentLinksByInterfaceType(
					ComponentInterface.INTERFACE_TYPE_INFO);
			mav.addObject("methodComponentLinks", methodComponentLinks_display);
			
			
			mav.setViewName("configDisplayDesignPatternComponent");
			return mav;
		case CONTROL:
			// List<InterfaceMethod> cInterfaceMethods =
			// interfaceMethodService.getAllInterfaceMethod();
			// mav.addObject("control_response_functions", cInterfaceMethods);

			List<MethodComponentLink> methodComponentLinks_control = methodComponentTool.getComponentLinksByInterfaceType(
					ComponentInterface.INTERFACE_TYPE_CONTROL_RESPONSE);
			mav.addObject("methodComponentLinks", methodComponentLinks_control);

			mav.setViewName("configControlDesignPatternComponent");
			mav.addObject("buttons", buttonService.getButtonByProject(project.getId()));

			DesignPatternComponent dpComponent = designPatternComponentService
					.getDesignPatternCommponentByType(designPatternCategoryId,
							DesignPatternType.DISPLAY);
			DesignPatternInstanceBean controlDpiBean = new DesignPatternInstanceBean(
					DesignPatternType.DISPLAY, dpComponent.getXmlPath());
			mav.addObject("exist_pages", controlDpiBean.getInstances());

			List<Map<String, Property>> controlMappings = dpiBean
					.getInstances();
			for (Map<String, Property> mapping : controlMappings) {
				Property pButton = mapping.get("button");
				pButton.setValue(buttonService.getButtonById(
						Long.parseLong(pButton.getValue())).getName());
				Property pType = mapping.get("type");
				if (pType.getValue().equals("function")) {
					Property pFunction = mapping.get("control_function");
					String[] link = pFunction.getValue().split("=");
					String methodSigniture = interfaceMethodService
							.getInterfaceMethodById(Long.parseLong(link[0]))
							.getMethodSigniture();
					logger.info("ID:" + link[0]);
					String methodComponentName = methodComponentService
							.getMethodComponentByUri(link[1]).getName();
					logger.info("URI:" + link[1]);
					pFunction.setValue(methodSigniture + "--"
							+ methodComponentName);
				}
			}
			mav.addObject("controlMappings", controlMappings);

			return mav;
		case IO:
			mav.setViewName("configIODesignPatternComponent");

			List<AvionicsEquipment> innerDevices = avionicsEquipmentService
					.getAvionicsEquipmentByType(AvionicsEquipment.EQUIPMENT_TYPE_INNER_DEVICE);
			
			
			mav.addObject("equipments", innerDevices);

			
			List<AvionicsEquipment> iInnerBusList = avionicsEquipmentService
					.getAvionicsEquipmentByType(AvionicsEquipment.EQUIPMENT_TYPE_BUS);
//			List<AvionicsEquipment> iInnerBusList = new ArrayList<AvionicsEquipment>();
//			for (AvionicsEquipment equipment : iEquipmentList) {
//				if (equipment.getEquiptype().equals(
//						AvionicsEquipment.EQUIPMENT_TYPE_BUS)) {
//					iInnerBusList.add(equipment);
//				}
//			}
			mav.addObject("inner_buses", iInnerBusList);

			List<Property> iProperties = dpiBean.getPropertyByName("equipment");
			List<AvionicsEquipment> iExistEquipments = new ArrayList<AvionicsEquipment>();
			for (Property p : iProperties) {
				AvionicsEquipment aEquipment = avionicsEquipmentService
						.getAvionicsEquipmentByUri(p.getValue());
				if (aEquipment != null)
					iExistEquipments.add(aEquipment);
			}
			mav.addObject("exist_equipments", iExistEquipments);

			return mav;

		}
		return mav;
	}
	
	@RequestMapping(value = {"/{projectId}/entityZone/{operation}"}, method = RequestMethod.GET)
	public ModelAndView getEntityZoneByProject(@PathVariable(value = "projectId")long projectId,
			@PathVariable(value = "operation")String operation){
		ModelAndView mav = new ModelAndView();
		
		List<EntityZoneCategory> entityZoneCategorys = entityZoneCategoryService.getEntityZoneCategoryByProject(projectId);
		mav.addObject("entityZoneCategorys", entityZoneCategorys);
		
		List<EntityZone> entityZones = entityZoneService.getEntityZoneByProject(projectId);
		mav.addObject("entityZones", entityZones);
		for (EntityZone entityZone : entityZones){
			DomainEntity entity = domainEntityService.getDomainEntityByUri(entityZone.getEntityUri());
			if (entity!=null){
				entityZone.setEntityUri(entity.getName());
			}
		}
		
		List<Project> projects = projectService.getProjectList();
		mav.addObject("projects", projects.iterator());
		
		Project project = projectService.getProjectById(projectId);
		mav.addObject("project", project);
		
		List<DomainEntity> domainEntities = domainEntityService
				.getAllDomainEntity();
		mav.addObject("domainEntitys", domainEntities);
		
		if ("edit".equals(operation)){
			mav.addObject("isEdit", Boolean.TRUE.toString());
		}
		
		mav.setViewName("configEntityZone");
		return mav;
	}
	

	@RequestMapping(value = "/addProjects", method = RequestMethod.GET)
	public ModelAndView addProject() {
		ModelAndView mav = new ModelAndView();
		mav.setViewName("addProjects");
		List<PGroup> pgroups = pgroupService.getPGroupList();
		mav.addObject("pgroups", pgroups.iterator());
		return mav;
	}
	
	@RequestMapping(value = "/addDesignPatternCategory", method = RequestMethod.GET)
	public ModelAndView addDesignPatternCategory() {
		ModelAndView mav = new ModelAndView();
		mav.setViewName("addDesignPatternCategory");
		List<PGroup> pgroups = pgroupService.getPGroupList();
		mav.addObject("pgroups", pgroups.iterator());
		return mav;
	}

	@RequestMapping(value = "/list/json", method = RequestMethod.GET)
	@ResponseBody
	public List<Project> getProjectJsonList() {
		User user = getUser();
		List<Project> projects = null;
		if (null != user) {
			projects = userProjectService.getProjectListByUser(user);
			logger.info(projects.size());
			for (Project p : projects) {
				p.setModel(null);
				p.setDesignPatternComponents(null);
				p.setOwner(null);
				p.setPgroup(null);
				logger.info(p.getName());
			}
		}
		return projects;
	}

	private User getUser() {
		Subject subject = SecurityUtils.getSubject();
		if (subject != null && subject.getPrincipals() != null) {
			CommonVariableModel model = (CommonVariableModel) subject
					.getPrincipals().getPrimaryPrincipal();
			return model.getUser();
		}
		return null;
	}

}
